#include "random.h"

static int trng_init(void)
{
	volatile mml_trng_regs_t	*reg_trng = (volatile mml_trng_regs_t*)MML_TRNG_IOBASE;

	reg_trng->trngcr = 0;
	reg_trng->trngcr |= ( MML_TRNGCN_RNG_EN_MASK | MML_TRNGCN_RNG_BS_MASK | MML_TRNGCN_RNG_ISC_MASK );

	
	// reg_trng->trngcr |= MML_TRNGCN_AESKG_MASK; 	// aes nvsram
	
	return NO_ERROR;
}

int trng_read(unsigned int *p_random, unsigned int length)
{
	int	result = COMMON_ERR_UNKNOWN;
	unsigned int	loop = 0;
	volatile mml_trng_regs_t *reg_trng = (volatile mml_trng_regs_t*)MML_TRNG_IOBASE;

	if ( reg_trng->trngcr & MML_TRNGCN_RNG_I4S_MASK )
	{
		for( loop = 0;loop < length;loop++ )
		{
			p_random[loop] = reg_trng->trngdr;
		}
	}
	
	reg_trng->trngcr |= MML_TRNGCN_RNG_ISC_MASK;
	loop = K_COBRA_TRNG_MAX_WAIT_LOOP;
	
	while( !( reg_trng->trngcr & MML_TRNGCN_RNG_I4S_MASK ) && loop-- );
	if ( !loop && !( reg_trng->trngcr & MML_TRNGCN_RNG_I4S_MASK ) )
	{
		result = N_COBRA_TRNG_ERR_FAILURE;
	}
	else
	{
		for( loop = 0;loop < length;loop++ )
		{
			p_random[loop] = reg_trng->trngdr;
		}
		result = NO_ERROR;
	}
	
	return result;
}	

int trng_gen_aes_key(unsigned char *p_pucKey, unsigned int p_uiLength)
{
	int	result = COMMON_ERR_UNKNOWN;

	if ( !p_pucKey )
	{
		result = COMMON_ERR_NULL_PTR;
		goto usecase_trng_gen_aes_key_output;
	}

	if ( K_COBRA_USECASE_TRNG_AES_KEY_SIZE != p_uiLength )
	{
		result = COMMON_ERR_INVAL;
		goto usecase_trng_gen_aes_key_output;
	}
	
	result = trng_init();
	if ( result )
	{
		goto usecase_trng_gen_aes_key_output;
	}

	//result = trng_read((unsigned int*)p_pucKey, ( p_uiLength / sizeof(unsigned int) ));

usecase_trng_gen_aes_key_output:
	return result;
}

/*
	for create AES key, then trans to nvsram
*/
int trng_aes_keygen(void)
{
	volatile mml_trng_regs_t		*mml_trng = (volatile mml_trng_regs_t*)MML_TRNG_IOBASE;
	u32 secdiag;

	mml_trng->trngcr |= MML_TRNGCN_AESKG_MASK;
	while(mml_trng->trngcr & MML_TRNGCN_AESKG_MASK); //wait until AESKG bit is cleared by HW

	rand_debug("[TRNG] trng_aes_keygen ... \n");

	IO_READ_U32(SECMON_SECDIAG, secdiag);
	if(secdiag & (1<<8)){
		return 0;
	}
	else{
		return 1;
	}
}

static u8 trng_calc_aes(u32 *user_key, u32 *data,  s8 user_select)
{
	mml_crypto_regs_t * crypto = (mml_crypto_regs_t *) MML_CRYPTO_IOBASE;
	
	crypto->crypto_control = MML_CRYPTO_CTRL_RST;	
	
	crypto->crypto_cipher_key_0 = user_key[0];	
	crypto->crypto_cipher_key_1 = user_key[1];	
	crypto->crypto_cipher_key_2 = user_key[2];	
	crypto->crypto_cipher_key_3 = user_key[3];

	if (user_select == 1)
		crypto->crypto_cipher_control = (MML_CRYPTO_CIPHER_CTRL_ENC + MML_CRYPTO_CIPHER_CTRL_MODE_ECB +  MML_CRYPTO_CIPHER_CTRL_CIPHER_AES_128 );
	else
		crypto->crypto_cipher_control = (MML_CRYPTO_CIPHER_CTRL_ENC + MML_CRYPTO_CIPHER_CTRL_MODE_ECB +  MML_CRYPTO_CIPHER_CTRL_CIPHER_AES_128 + 0x08);
	
	crypto->crypto_DIN_0 = data[0];
	crypto->crypto_DIN_1 = data[1];
	crypto->crypto_DIN_2 = data[2];
	crypto->crypto_DIN_3 = data[3];

	while((crypto->crypto_control & MML_CRYPTO_CTRL_DONE) != MML_CRYPTO_CTRL_DONE);
	
	data[0] = crypto->crypto_DOUT_0;
	data[1] = crypto->crypto_DOUT_1;
	data[2] = crypto->crypto_DOUT_2;
	data[3] = crypto->crypto_DOUT_3;

	return 0;
}

u8  trng_check_aes_valid(void)
{
	unsigned int data[4], user_key[4];
	u8 result = 0;

	data[0] = 0x00000000;
	data[1] = 0x00000000;
	data[2] = 0x00000000;
	data[3] = 0x00000000;

	trng_calc_aes(user_key, data, 0);
	
	/** if keywipe has been performed, the secure AES key is 0x0000000...000 */
	if ( (data[3] == 0x2e2b34ca) && (data[2] == 0x59fa4c88) && (data[1] == 0x3b2c8aef) && (data[0] == 0xd44be966) )
	{
		result = 1;
	}
	else
	{
		result = 0;
	}

	return result;
}

